﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using Estructuras.Comunes;
using Estructuras.Funciones.Analizar;

namespace Estructuras.Consola.ConsolaAnalizarDatos
{
    /// <summary>
    /// Tipos posibles de los nodos de definicion de datos.
    /// </summary>
    public enum TiposNodosDefinicionDatos
    {
        Valor,
        Enlace,
        Mascara
    };

    /// <summary>
    /// Clase de conversión usada para convertir la cadena dada a un tipo de nodo definición de datos.
    /// </summary>
    public static class ConversorTiposNodosDefinicionDatos
    {
        /// <summary>
        /// Convierte la cadena proporcionada en un tipo de nodo de definición de datos válido.
        /// </summary>
        /// <param name="tipo">Cadena con el tipo de nodo</param>
        /// <returns>Tipo de nodo de definición de datos</returns>
        public static TiposNodosDefinicionDatos Convertir(string tipo)
        {
            switch (tipo)
            {
                case "Valor":
                    return TiposNodosDefinicionDatos.Valor;
                case "Enlace":
                    return TiposNodosDefinicionDatos.Enlace;
                case "Mascara":
                    return TiposNodosDefinicionDatos.Mascara;
                default:
                    throw new Excepcion(Estructuras.Comunes.Constantes.ERROR_TIPO_NODO_DEFINICION_DATOS_NO_DEFINIDO, Estructuras.Comunes.Constantes.CODIGO_ERROR_TIPO_NODO_DEFINICION_DATOS_NO_DEFINIDO);
            }
        } 
    }

    /// <summary>
    /// Almacena las propiedades de un elemento específico.
    /// </summary>
    public class PDefinicionDatos : Propiedades
    {
        /// <summary>
        /// Diccionario Valores.
        /// </summary>
        public Dictionary<string, Valor> DiccionarioValores
        {
            get
            {
                if (!this.contienePropiedad(CDefinicionDatos.DiccionarioValores))
                    this.addPropiedad(CDefinicionDatos.DiccionarioValores, new Dictionary<string, Valor>());
                return (Dictionary<string, Valor>)this.getPropiedad(CDefinicionDatos.DiccionarioValores);
            }
            set
            {
                this.setOrAddPropiedad(CDefinicionDatos.DiccionarioValores, value);
            }
        }

        /// <summary>
        /// Diccionario Máscaras.
        /// </summary>
        public Dictionary<string, Mascara> DiccionarioMascaras
        {
            get
            {
                if (!this.contienePropiedad(CDefinicionDatos.DiccionarioMascaras))
                    this.addPropiedad(CDefinicionDatos.DiccionarioMascaras, new Dictionary<string, Mascara>());
                return (Dictionary<string, Mascara>)this.getPropiedad(CDefinicionDatos.DiccionarioMascaras);
            }
            set
            {
                this.setOrAddPropiedad(CDefinicionDatos.DiccionarioMascaras, value);
            }
        }

        /// <summary>
        /// Constructor por defecto.
        /// </summary>
        public PDefinicionDatos()
            : base()
        {
        }

        /// <summary>
        /// Obtiene los parámetros a partir del fichero XML indicado.
        /// </summary>
        /// <param name="fichero">Fichero de configuración XML</param>
        override public void leer(string fichero)
        {
            base.leer(fichero);
            XmlDocument xml = null;
            try
            {
                xml = LeerXml.AbrirFicheroParametros(fichero);
            }
            catch (Exception)
            {
                throw new Excepcion(Estructuras.Comunes.Constantes.ERROR_CARGAR_FICHERO_DEFINICION_DATOS, Estructuras.Comunes.Constantes.CODIGO_ERROR_CARGAR_FICHERO_DEFINICION_DATOS);
            }

            try
            {
                // Datos
                int numeroDatos = LeerXml.ObtenerNumeroNodosCampo(xml, CDefinicionDatos.RutaNodoRaiz);
                this.DiccionarioValores = new Dictionary<string, Valor>();
                this.DiccionarioMascaras = new Dictionary<string, Mascara>();
                for (int indiceDato = 0; indiceDato < numeroDatos; indiceDato++)
                {
                    string tipo = LeerXml.ObtenerValorCampo(xml, CDefinicionDatos.RutaNodoRaiz, indiceDato, CDefinicionDatos.NodoDatoTipo);
                    string valor = LeerXml.ObtenerValorCampo(xml, CDefinicionDatos.RutaNodoRaiz, indiceDato, CDefinicionDatos.NodoDatoValor);
                    string salida = string.Empty;
                    try
                    { salida = LeerXml.ObtenerValorCampo(xml, CDefinicionDatos.RutaNodoRaiz, indiceDato, CDefinicionDatos.NodoDatoSalida); }
                    catch (Exception)
                    { salida = string.Empty; }
                    if (TiposNodosDefinicionDatos.Valor.Equals(ConversorTiposNodosDefinicionDatos.Convertir(tipo)))
                    {
                        // Valor
                        string tag = LeerXml.ObtenerValorCampo(xml, CDefinicionDatos.RutaNodoRaiz, indiceDato, CDefinicionDatos.NodoDatoTag);
                        if (!string.Empty.Equals(tag))
                        {
                            if (this.DiccionarioValores.ContainsKey(valor))
                                this.DiccionarioValores[valor] = new Valor(tag, salida);
                            else
                                this.DiccionarioValores.Add(valor, new Valor(tag, salida));
                            
                            // Otros tags
                            this.DiccionarioValores[valor].OtrosTags = new Dictionary<string, string>();
                            int numeroOtrosTags = LeerXml.ObtenerNumeroNodosCampo(xml, CDefinicionDatos.RutaNodoRaiz, indiceDato, CDefinicionDatos.NodoDatoOtrosTags);
                            for (int indiceOtros = 0; indiceOtros < numeroOtrosTags; indiceOtros++)
                            {
                                string alias = LeerXml.ObtenerValorCampo(xml, CDefinicionDatos.RutaNodoRaiz, indiceDato, CDefinicionDatos.NodoDatoOtrosTags, indiceOtros, CDefinicionDatos.NodoDatoOtrosTagsTagAlias);
                                string valorAlias = LeerXml.ObtenerValorCampo(xml, CDefinicionDatos.RutaNodoRaiz, indiceDato, CDefinicionDatos.NodoDatoOtrosTags, indiceOtros, CDefinicionDatos.NodoDatoOtrosTagsTagValor);
                                if (!string.Empty.Equals(alias))
                                    this.DiccionarioValores[valor].OtrosTags.Add(alias, valorAlias);
                            }
                        }
                    }
                    else if (TiposNodosDefinicionDatos.Enlace.Equals(ConversorTiposNodosDefinicionDatos.Convertir(tipo)))
                    {
                        // Enlace
                        if (this.DiccionarioValores.ContainsKey(valor))
                            this.DiccionarioValores[valor] = new Valor(salida);
                        else
                            this.DiccionarioValores.Add(valor, new Valor(salida));
                    }
                    else if (TiposNodosDefinicionDatos.Mascara.Equals(ConversorTiposNodosDefinicionDatos.Convertir(tipo)))
                    {
                        // Máscara
                        string tag = LeerXml.ObtenerValorCampo(xml, CDefinicionDatos.RutaNodoRaiz, indiceDato, CDefinicionDatos.NodoDatoTag);
                        if (this.DiccionarioMascaras.ContainsKey(valor))
                            this.DiccionarioMascaras[valor] = new Mascara(salida, tag);
                        else
                            this.DiccionarioMascaras.Add(valor, new Mascara(salida, tag));
                    }
                }
            }
            catch (Exception)
            {
                throw new Excepcion(Estructuras.Comunes.Constantes.ERROR_OBTENER_DEFINICION_DATOS, Estructuras.Comunes.Constantes.CODIGO_ERROR_OBTENER_DEFINICION_DATOS);
            }
        }
    }
}

